/* Copyright (c) [2025] [zhi1208@126.com]
 * SPDX-License-Identifier: MIT
 */

/*********************
 *      INCLUDES
 *********************/
#include <stdint.h>

#include "FreeRTOS.h"
#include "task.h"

#include "main.h"
#include "bsp_sw_i2c.h"
#include "bsp_delay_us.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/
typedef struct
{
    uint8_t index;
    uint8_t data_addr;
    uint8_t len;
} kv_index_t;

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void set_scl_with_delay(uint8_t value);
static void set_sda_with_delay(uint8_t value);
static uint8_t read_sda();
static uint8_t write_byte(const uint8_t addr, const uint8_t data);

/**********************
 *  STATIC VARIABLES
 **********************/
static sw_i2c_t at24c02_sw_i2c = {
    .wr_addr = 0xa0,
    .rd_addr = 0xa1,
    .set_scl = set_scl_with_delay,
    .set_sda = set_sda_with_delay,
    .read_sda = read_sda};

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
uint8_t bsp_at24c02_read_data(const uint8_t addr, uint8_t *data, const uint8_t length)
{
    sw_i2c_start(&at24c02_sw_i2c);

    sw_i2c_send_byte(&at24c02_sw_i2c, at24c02_sw_i2c.wr_addr);
    if (sw_i2c_recv_ack(&at24c02_sw_i2c))
        return 0;

    sw_i2c_send_byte(&at24c02_sw_i2c, addr);
    if (sw_i2c_recv_ack(&at24c02_sw_i2c))
        return 0;

    sw_i2c_start(&at24c02_sw_i2c);

    sw_i2c_send_byte(&at24c02_sw_i2c, at24c02_sw_i2c.rd_addr);
    if (sw_i2c_recv_ack(&at24c02_sw_i2c))
        return 0;

    for (uint32_t i = 0; i < length - 1; ++i)
    {
        data[i] = sw_i2c_recv_byte(&at24c02_sw_i2c);
        sw_i2c_send_ack(&at24c02_sw_i2c, 0);
    }
    data[length - 1] = sw_i2c_recv_byte(&at24c02_sw_i2c);
    sw_i2c_send_ack(&at24c02_sw_i2c, 1);

    sw_i2c_stop(&at24c02_sw_i2c);

    return 1;
}

uint8_t bsp_at24c02_write_data(const uint8_t addr, const uint8_t *data, const uint8_t length)
{
    for (uint8_t i = 0; i < length; ++i)
    {
        if (!write_byte(addr + i, data[i]))
            return 0;

        vTaskDelay(pdMS_TO_TICKS(5));
    }

    return 1;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
static void set_scl_with_delay(uint8_t value)
{
    HAL_GPIO_WritePin(AT24C02_SCL_GPIO_Port, AT24C02_SCL_Pin, (GPIO_PinState)value);
    bsp_delay_us(10);
}

static void set_sda_with_delay(uint8_t value)
{
    HAL_GPIO_WritePin(AT24C02_SDA_GPIO_Port, AT24C02_SDA_Pin, (GPIO_PinState)value);
    bsp_delay_us(10);
}

static uint8_t read_sda()
{
    return HAL_GPIO_ReadPin(AT24C02_SDA_GPIO_Port, AT24C02_SDA_Pin);
}

static uint8_t write_byte(const uint8_t addr, const uint8_t data)
{
    sw_i2c_start(&at24c02_sw_i2c);

    sw_i2c_send_byte(&at24c02_sw_i2c, at24c02_sw_i2c.wr_addr);
    if (sw_i2c_recv_ack(&at24c02_sw_i2c))
        return 0;

    sw_i2c_send_byte(&at24c02_sw_i2c, addr);
    if (sw_i2c_recv_ack(&at24c02_sw_i2c))
        return 0;

    sw_i2c_send_byte(&at24c02_sw_i2c, data);
    if (sw_i2c_recv_ack(&at24c02_sw_i2c))
        return 0;

    sw_i2c_stop(&at24c02_sw_i2c);

    return 1;
}